package libra.forSentinel.openFeign;

import java.util.HashMap;
import java.util.Map;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;

/**
 * 使用@FeignClient注解标识OpenFeign定义的服务调用接口类，且该组件必须存在于容器内
 * 基于Feign的客户端负载均衡技术
 * 接口式、注解式编程
 * @FeignClient()：使用Feign负载均衡
 * name/value：指定被调用的微服务，填写spring.application.name微服务名，调用服务名，使用注册服务名即可不关心ip、port
 * path: 定义当前FeignClient的统一前缀，当我们项目中配置了server.context-path,server.servlet-path时使用
 *** @FeignClient只关心服务名，即ip、port；如果有项目名的话，需要在对应接口请求地址中进行补全 ***
 *** fallbackFactory属性用来处理通用的“服务降级”，OpenFeign自身无法独立完成该功能点，需要配合Hystrix处理 ***
 */
@FeignClient( name = "nacos-sentinel-provider", 
//		fallback = FallBackImpl.class,
		fallbackFactory = FallBackFactoryImpl.class, 
		path = "nacos_sentinel_provider_30700")
public interface FeignClientInter {
	// 流控 - QPS测试
	@PostMapping("/forConsumer/testFlowQps")
	public Map<String, String> testFlowQps( @RequestParam("exFlag") Boolean exFlag );
	
	// 流控 - QPS测试
	@PostMapping("/forConsumer/testDegrade")
	public Map<String, String> testDegrade( @RequestParam("exFlag") Boolean exFlag, @RequestParam("exType") Integer exType );
	
	/**
	 * 接口中定义默认方法，用于统一处理OpenFeign的调用fallback
	 * @param cause
	 * @return
	 */
	public default Map<String, String> fixFallback( Class from, Throwable cause ){
		Map<String, String> map = new HashMap<>();
		map.put("from", from.getName());
		if( cause != null ) {
			if( cause instanceof BlockException ) {
				BlockException e = (BlockException) cause;
				//getRule()返回资源、规则的详细信息
//				System.out.println( e.getRule() );
				String info = "";
				map.put("Sentinel_Exception_Type", e.getClass().getSimpleName());
				if ( e instanceof FlowException ) {
					 info = String.format("流控异常，请求【testFlowQps】，异常【%s】", e.getClass().getSimpleName() );
				} else if ( e instanceof DegradeException ) {
					 info = String.format("熔断异常，请求【testFlowQps】，异常【%s】", e.getClass().getSimpleName() );
				} else if ( e instanceof ParamFlowException ) {
					 info = String.format("热点key异常，请求【%s】，异常【%s】", e.getClass().getSimpleName() );
				} else if ( e instanceof SystemBlockException ) {
					 info = String.format("系统保护异常，请求【%s】，异常【%s】", e.getClass().getSimpleName() );
				} else if ( e instanceof AuthorityException ) {
					 info = String.format("授权异常，请求【%s】，异常【%s】", e.getClass().getSimpleName() );
				} else {
					info = String.format("执行异常，请求【%s】，异常【%s】", e.getClass().getSimpleName() );
				}
				e.printStackTrace();
			} else {
				map.put("Other_Exception_Type", cause.getClass().getSimpleName());
			}
//			cause.printStackTrace();
		}
		return map;
	}
}
